﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Simulator;
using System.Threading;

namespace ModelConfigurator
{
    public partial class FormOptimizer : FormBase
    {
        /// <summary>
        /// Экземпляр класса оптимизатора
        /// </summary>
        public SimOptimizer Optimizer { get; set; }
        /// <summary>
        /// Названия доп. параметров
        /// </summary>
        public List<string> ParamNames { get; set; }

        public FormOptimizer()
        {
            InitializeComponent();
        }

        delegate void UpdateAll(bool b);
        /// <summary>
        /// Обновить статус-бар
        /// </summary>
        private void OnNotify(bool b)
        {
            UpdateAll uo = UpdateFormOut;
            this.Invoke(uo, b);
        }

        private void UpdateFormOut(bool b)
        {//вызываем эту ф-цию на каждом шаге оптимизации
            //заполняется таблица
            dataGridViewParams[1, 2].Value = Optimizer.BestSim.Tavr.ToString("N3");
            for (int i = 0; i < ParamNames.Count; i++)
            {
                dataGridViewParams[2 + i, 2].Value = Optimizer.BestSim.GetTotalParam(i).ToString("N0");
            }
            //изменяется значение метки
            labelCrit.Text = "Значение обобщенного критерия текущей модели: Cr = " + Optimizer.GetGeneralizedCriterion(Optimizer.BestSim);
            if (b)
                labelCrit.Text += ". Оптимизация может быть остановлена";
        }

        private void FormOptimizer_Load(object sender, EventArgs e)
        {
            Optimizer.OnNotify = OnNotify;//вызываем эту ф-цию на каждом шаге оптимизации


            numericUpDownTime.Value = Optimizer.StartModel.SimulationTime;
            //настроим время
            switch (Optimizer.StartModel.SimulationTimeUnits)
            {
                case TimeUnits.days:
                    comboBoxTime.SelectedItem = comboBoxTime.Items[0];
                    break;
                case TimeUnits.hours:
                    comboBoxTime.SelectedItem = comboBoxTime.Items[1];
                    break;
                case TimeUnits.minutes:
                    comboBoxTime.SelectedItem = comboBoxTime.Items[2];
                    break;
                default:
                    comboBoxTime.SelectedItem = comboBoxTime.Items[3];
                    break;
            }

            numericRepeat.Value = Convert.ToDecimal(Optimizer.NRepeat);

            FillTable();

            checkBoxMult.Checked = Optimizer.ChangeMultiplicity;
            checkBoxReplace.Checked = Optimizer.ChangeAtomicRes;

            //если неизвестно значение Tavr, получим хотя бы 1 прогон модели
            if (Optimizer.StartModel.Tavr == 0)
            {
                Optimizer.StartModel.Tavr = Optimizer.StartModel.RunOnce();
            }
            labelCrit.Text = "Значение обобщенного критерия текущей модели: Cr = " + Optimizer.GetGeneralizedCriterion(Optimizer.StartModel);
        }

        private void FillTable()
        {
            //настроим таблицу
            //добавим столбцы
            int i = 0;
            foreach (string s in ParamNames)
            {
                dataGridViewParams.Columns.Add("Column" + i, s);
                if (s == "")
                    dataGridViewParams.Columns["Column" + i].Visible = false;
                i++;
            }
            //впишем строки
            dataGridViewParams.Rows.Add(2);
            dataGridViewParams[0, 0].Value = "Веса параметров";
            dataGridViewParams[0, 1].Value = "Ограничения";
            //заполним параметры

            for (i = 0; i < Optimizer.ParamWeights.Count; i++)
            {
                double d = Optimizer.ParamWeights[i];
                //сделаем нулевыми веса и ограничения при пустых параметрах
                if (dataGridViewParams.Columns[i+1].Visible != false)
                    dataGridViewParams[i+1, 0].Value = d.ToString("N2");
                else
                    Optimizer.ParamWeights[i] = 0;

            }
            //заполним ограничения
            for (i = 0; i < Optimizer.ParamConstraints.Count; i++)
            {
                double d = Optimizer.ParamWeights[i];
                //сделаем нулевыми веса и ограничения при пустых параметрах
                if (dataGridViewParams.Columns[i+1].Visible != false)
                    dataGridViewParams[i+1, 1].Value = d.ToString("N2");
                else
                    Optimizer.ParamConstraints[i] = 0;

            }
        }

        private void checkBoxMult_CheckedChanged(object sender, EventArgs e)
        {
            Optimizer.ChangeMultiplicity = checkBoxMult.Checked;

        }

        private void checkBoxReplace_CheckedChanged(object sender, EventArgs e)
        {
            Optimizer.ChangeAtomicRes = checkBoxReplace.Checked;
        }

        private void numericRepeat_ValueChanged(object sender, EventArgs e)
        {
            Optimizer.NRepeat = Convert.ToInt32(numericRepeat.Value);
        }

        private void numericUpDownTime_ValueChanged(object sender, EventArgs e)
        {
            Optimizer.StartModel.SimulationTime = numericUpDownTime.Value;
        }

        private void comboBoxTime_SelectedIndexChanged(object sender, EventArgs e)
        {
            SimModel Sim = Optimizer.StartModel;
            //настроим единицы измерения времени
            switch (comboBoxTime.SelectedIndex)
            {
                case 0:
                    Sim.SimulationTimeUnits = TimeUnits.days;
                    break;
                case 1:
                    Sim.SimulationTimeUnits = TimeUnits.hours;
                    break;
                case 2:
                    Sim.SimulationTimeUnits = TimeUnits.minutes;
                    break;
                default:
                    Sim.SimulationTimeUnits = TimeUnits.seconds;
                    break;
            }
        }

        private void dataGridViewParams_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            //настроим соотв. параметр
            int i = e.ColumnIndex;
            int j = e.RowIndex;
            string s = Convert.ToString(dataGridViewParams[i, j].Value);
            if (CheckDouble(s, sender as Control))//если это число
            {
                switch (j)
                {
                    case 0:
                        Optimizer.ParamWeights[i-1] = Convert.ToDouble(s);
                        break;
                    default:
                        // == case 1:
                        Optimizer.ParamConstraints[i-1] = Convert.ToDouble(s);
                        break;
                }
                //перестроим метку
                labelCrit.Text = "Значение обобщенного критерия текущей модели: Cr = " + Optimizer.GetGeneralizedCriterion(Optimizer.StartModel);
            }
        }

        /// <summary>
        /// Проверка, является ли текст числом типа Double. Если нет, выз. ErrorProvider
        /// </summary>
        /// <param name="s">Текстовая строка</param>
        /// <param name="ctr">Элемент управления, которому присвоится ErrorProvider</param>
        /// <returns>ИСТИНА если является double, иначе ЛОЖЬ</returns>
        private bool CheckDouble(string s, Control ctr)
        {
            bool b = true;
            errorProvider1.Clear();
            try
            {
                Convert.ToDouble(s);
            }
            catch
            {
                b = false;
                errorProvider1.SetError(ctr, "В ячейку можно ввести только число типа double");
            }
            return b;
        }

        private void buttonPlay_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(RunCycle);

            buttonPause.Enabled = true;
            buttonStop.Enabled = true;
            buttonPlay.Enabled = false;

            dataGridViewParams.ReadOnly = true;
            if (dataGridViewParams.Rows.Count < 3)
            {
                dataGridViewParams.Rows.Add();
                dataGridViewParams[0, 2].Value = "Параметры лучшей модели";
                dataGridViewParams.Rows[2].ReadOnly = true;
            }

            t.Start();
        }

        private void RunCycle()
        {
            Optimizer.Run();
            //функция выполнилась, отобразим результаты
            //по окончании прервем текущий поток
            Thread.CurrentThread.Interrupt();
        }

        private void buttonPause_Click(object sender, EventArgs e)
        {
            Optimizer.Pause();
            buttonStop.Enabled = true;
            buttonPause.Enabled = false;
            buttonPlay.Enabled = true;
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            Optimizer.Stop();
            dataGridViewParams.ReadOnly = false;
            buttonStop.Enabled = false;
            buttonPause.Enabled = false;
            buttonPlay.Enabled = true;
        }

        private void buttonOK_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
            this.Close();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.Close();

        }

        private void dataGridViewParams_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }

        private void buttonHelp_Click(object sender, EventArgs e)
        {
            string openCHMFile = Application.StartupPath + "\\Справка SAPR-SIM.chm";
            try
            {
                if (!System.IO.File.Exists(openCHMFile))
                    System.IO.File.WriteAllBytes(openCHMFile, global::ModelConfigurator.Properties.Resources.Справка_SAPR_SIM);
            }
            catch
            {
                //если файл есть он не перепишется
            }
            helpProvider1.HelpNamespace = openCHMFile;
            Help.ShowHelp(this, this.helpProvider1.HelpNamespace, HelpNavigator.Topic, "module_2.htm");
        }



    }
}
